// ==++==
// 
//   
//    Copyright (c) 2006 Microsoft Corporation.  All rights reserved.
//   
//    The use and distribution terms for this software are contained in the file
//    named license.txt, which can be found in the root of this distribution.
//    By using this software in any fashion, you are agreeing to be bound by the
//    terms of this license.
//   
//    You must not remove this notice, or any other, from this software.
//   
// 
// ==--==
/******************************************************************************/
/*                                 formatType.cpp	                          */
/******************************************************************************/

#include "specstrings.h"
#include "formattype.h"
#include "utilcode.h"					// for CQuickBytes 
#include <sstring.h>


#ifdef __ILDASM__

BOOL					g_fQuoteAllNames = FALSE; // used by ILDASM
BOOL                    g_fDumpTokens = FALSE;	  // used by ILDASM
LPCSTR					*rAsmRefName = NULL;	  // used by ILDASM
ULONG					ulNumAsmRefs = 0;		  // used by ILDASM
BOOL                    g_fDumpRTF = FALSE;		  // used by ILDASM
BOOL                    g_fDumpHTML = FALSE;      // used by ILDASM
BOOL                    g_fUseProperName = FALSE; // used by ILDASM
DynamicArray<mdToken>   *g_dups = NULL;           // used by ILDASM
DWORD                   g_NumDups=0;              // used by ILDASM
DynamicArray<TypeDefDescr>   *g_typedefs = NULL;           // used by ILDASM
DWORD                   g_NumTypedefs=0;              // used by ILDASM
 
// buffers created in Init and deleted in Uninit (dasm.cpp)
CQuickBytes             * g_szBuf_KEYWORD  = NULL;
CQuickBytes             * g_szBuf_COMMENT  = NULL;
CQuickBytes             * g_szBuf_ERRORMSG = NULL;
CQuickBytes             * g_szBuf_ANCHORPT = NULL;
CQuickBytes             * g_szBuf_JUMPPT  = NULL;
CQuickBytes             * g_szBuf_UnquotedProperName = NULL;
CQuickBytes             * g_szBuf_ProperName = NULL;

// Protection against null names, used by ILDASM
char* szStdNamePrefix[] = {"MO","TR","TD","","FD","","MD","","PA","II","MR","","CA","","PE","","","SG","","","EV",
"","","PR","","","MOR","TS","","","","","AS","","","AR","","","FL","ET","MAR"};

//-------------------------------------------------------------------------------
// Reference analysis (ILDASM)
DynamicArray<TokPair>    *g_refs = NULL;
DWORD                    g_NumRefs=0;
mdToken                  g_tkRefUser=0; // for PrettyPrintSig

mdToken                  g_tkVarOwner = 0;
mdToken                  g_tkMVarOwner = 0;

#endif

/******************************************************************************/
char* asString(CQuickBytes *out) {
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
    SIZE_T oldSize = out->Size();
    out->ReSizeThrows(oldSize + 1);
    char* cur = &((char*) out->Ptr())[oldSize]; 
    *cur = 0;   
    out->ReSizeThrows(oldSize);   		// Don't count the null character
    return((char*) out->Ptr()); 
}

void appendStr(CQuickBytes *out, const char* str, unsigned len) {
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
    if(len == (unsigned)(-1)) len = (unsigned)strlen(str); 
    SIZE_T oldSize = out->Size();
    out->ReSizeThrows(oldSize + len);
    char* cur = &((char*) out->Ptr())[oldSize]; 
    memcpy(cur, str, len);  
        // Note no trailing null!   
}

void appendChar(CQuickBytes *out, char chr) {
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
    SIZE_T oldSize = out->Size();
    out->ReSizeThrows(oldSize + 1); 
    ((char*) out->Ptr())[oldSize] = chr; 
        // Note no trailing null!   
}

void insertStr(CQuickBytes *out, const char* str) {
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
    unsigned len = (unsigned)strlen(str); 
    SIZE_T oldSize = out->Size();
    out->ReSizeThrows(oldSize + len); 
    char* cur = &((char*) out->Ptr())[len];
	memmove(cur,out->Ptr(),oldSize);
    memcpy(out->Ptr(), str, len);  
        // Note no trailing null!   
}

static void appendStrNum(CQuickBytes *out, int num) {
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
    char buff[16];  
    sprintf_s(buff, COUNTOF(buff), "%d", num);   
    appendStr(out, buff);   
}

#ifdef __ILDASM__

// Special dumping routines for keywords, comments and errors, used by ILDASM
/*
void strcatHTML(char* szOut, char* szIn)
{
    char* pcOut = &szOut[strlen(szOut)];
    do
    {
        switch(*szIn)
        {
            case '<':
                pcOut += sprintf(pcOut,"&lt;");
                break;
            case '>':
                pcOut += sprintf(pcOut,"&gt;");
                break;
            case '&':
                pcOut += sprintf(pcOut,"&amp;");
                break;
            case '"':
                pcOut += sprintf(pcOut,"&quot;");
                break;
            default:
                *pcOut = *szIn;
                pcOut++;
                break;
        }
        szIn++;
    } while(*szIn);
    *pcOut = 0;
}
*/
char* KEYWORD(__in_opt __nullterminated char* szOrig)
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
	char* szPrefix = "";
	char* szPostfix = "";
	if(g_fDumpHTML)
	{
		szPrefix = "<B><FONT COLOR=NAVY>";
		szPostfix = "</FONT></B>";
	}
	else if(g_fDumpRTF)
	{
		szPrefix = "\\b\\cf1 ";
		szPostfix = "\\cf0\\b0 ";
	}
    if(szOrig == NULL) return szPrefix;
    if(szOrig == (char*)-1) return szPostfix;
    if(*szPrefix)
	{
        g_szBuf_KEYWORD->Shrink(0);
		appendStr(g_szBuf_KEYWORD,szPrefix);
		appendStr(g_szBuf_KEYWORD,szOrig);
		appendStr(g_szBuf_KEYWORD,szPostfix);
		return asString(g_szBuf_KEYWORD);
	}
	else
		return szOrig;
}
char* COMMENT(__in_opt __nullterminated char* szOrig)
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
	char* szPrefix = "";
	char* szPostfix = "";
	if(g_fDumpHTML)
	{
		szPrefix = "<I><FONT COLOR=GREEN>";
		szPostfix = "</FONT></I>";
	}
	else if(g_fDumpRTF)
	{
		szPrefix = "\\cf2\\i ";
		szPostfix = "\\i0\\cf0 ";
	}
	else
	{
		szPrefix = "";
		szPostfix = "";
	}
    if(szOrig == NULL) return szPrefix;
    if(szOrig == (char*)-1) return szPostfix;
    if(*szPrefix)
	{
        g_szBuf_COMMENT->Shrink(0);
		appendStr(g_szBuf_COMMENT,szPrefix);
		appendStr(g_szBuf_COMMENT,szOrig);
		appendStr(g_szBuf_COMMENT,szPostfix);
		return asString(g_szBuf_COMMENT);
	}
	else
		return szOrig;
}
char* ERRORMSG(__in_opt __nullterminated char* szOrig)
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
	char* szPrefix = "";
	char* szPostfix = "";
	if(g_fDumpHTML)
	{
		szPrefix = "<I><B><FONT COLOR=RED>";
		szPostfix = "</FONT></B></I>";
	}
	else if(g_fDumpRTF)
	{
		szPrefix = "\\cf3\\i\\b ";
		szPostfix = "\\cf0\\b0\\i0 ";
	}
    if(szOrig == NULL) return szPrefix;
    if(szOrig == (char*)-1) return szPostfix;
    if(*szPrefix)
	{
        g_szBuf_ERRORMSG->Shrink(0);
		appendStr(g_szBuf_ERRORMSG,szPrefix);
		appendStr(g_szBuf_ERRORMSG,szOrig);
		appendStr(g_szBuf_ERRORMSG,szPostfix);
		return asString(g_szBuf_ERRORMSG);
	}
	else
		return szOrig;
}

char* ANCHORPT(__in __nullterminated char* szOrig, mdToken tk)
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
	if(g_fDumpHTML)
	{
		char  szPrefix[64];
		char* szPostfix = "</A>";
		sprintf_s(szPrefix, COUNTOF(szPrefix), "<A NAME=A%08X>",tk);
        g_szBuf_ANCHORPT->Shrink(0);
		appendStr(g_szBuf_ANCHORPT,szPrefix);
		appendStr(g_szBuf_ANCHORPT,szOrig);
		appendStr(g_szBuf_ANCHORPT,szPostfix);
		return asString(g_szBuf_ANCHORPT);
	}
	else
		return szOrig;
}
char* JUMPPT(__in __nullterminated char* szOrig, mdToken tk)
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
	if(g_fDumpHTML)
	{
		char  szPrefix[64];
		char* szPostfix = "</A>";
		sprintf_s(szPrefix,COUNTOF(szPrefix), "<A HREF=#A%08X>",tk);
        g_szBuf_JUMPPT->Shrink(0);
		appendStr(g_szBuf_JUMPPT,szPrefix);
		appendStr(g_szBuf_JUMPPT,szOrig);
		appendStr(g_szBuf_JUMPPT,szPostfix);
        return asString(g_szBuf_JUMPPT);
	}
	else
		return szOrig;
}
const char* SCOPE(void) { return g_fDumpRTF ? "\\{" : "{"; }
const char* UNSCOPE(void) { return g_fDumpRTF ? "\\}" : "}"; }
const char* LTN(void) { return g_fDumpHTML ? "&lt;" : "<"; }
const char* GTN(void) { return g_fDumpHTML ? "&gt;" : ">"; }
const char* AMP(void) { return g_fDumpHTML ? "&amp;" : "&"; }

#endif


const PCCOR_SIGNATURE PrettyPrintSignature(
    PCCOR_SIGNATURE typePtr,            // type to convert,     
	unsigned typeLen,					// the lenght of 'typePtr' 
    const char* name,                   // can be "", the name of the method for this sig 0 means local var sig 
    CQuickBytes *out,                   // where to put the pretty printed string   
    IMDInternalImport *pIMDI,           // ptr to IMDInternalImport class with ComSig
	__in_opt const char* inlabel,				// prefix for names (NULL if no names required)
    BOOL printTyArity=FALSE);


PCCOR_SIGNATURE PrettyPrintTypeOrDef(
    PCCOR_SIGNATURE typePtr,            // type to convert,     
    CQuickBytes *out,                   // where to put the pretty printed string   
    IMDInternalImport *pIMDI);          // ptr to IMDInternal class with ComSig

//*****************************************************************************
// Parse a length, return the length, size of the length.
//*****************************************************************************
ULONG GetLength(			// Length or -1 on error.
	void const	*pData, 				// First byte of length.
	int			*pSizeLen)				// Put size of length here, if not 0.
{
    LEAF_CONTRACT;

	BYTE const	*pBytes = reinterpret_cast<BYTE const*>(pData);

	if(pBytes)
	{
		if ((*pBytes & 0x80) == 0x00)		// 0??? ????
		{
			if (pSizeLen) *pSizeLen = 1;
			return (*pBytes & 0x7f);
		}

		if ((*pBytes & 0xC0) == 0x80)		// 10?? ????
		{
			if (pSizeLen) *pSizeLen = 2;
			return ((*pBytes & 0x3f) << 8 | *(pBytes+1));
		}

		if ((*pBytes & 0xE0) == 0xC0)		// 110? ????
		{
			if (pSizeLen) *pSizeLen = 4;
			return ((*pBytes & 0x1f) << 24 | *(pBytes+1) << 16 | *(pBytes+2) << 8 | *(pBytes+3));
		}
	}
	if(pSizeLen) *pSizeLen = 0;
	return 0;
}

#ifdef __ILDASM__

/******************************************************************************/
// Function: convert spec.symbols to esc sequences and single-quote if necessary
char* UnquotedProperName(__in __nullterminated char* name, unsigned len/*=(unsigned)-1*/)
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
    CQuickBytes *buff = g_szBuf_UnquotedProperName;
    _ASSERTE (buff);
    if(g_fUseProperName)
    {
    	char *pcn,*pcend,*ret;
    	if(name)
    	{
    		if(*name)
    		{
    			pcn = name;
                if(len == (unsigned)(-1)) len = (unsigned)strlen(name);
                pcend = pcn + len;
                buff->Shrink(0);
    			for(pcn=name; pcn < pcend; pcn++) 
                {
    				switch(*pcn)
    				{
    					case '\t': appendChar(buff,'\\'); appendChar(buff,'t'); break;
    					case '\n': appendChar(buff,'\\'); appendChar(buff,'n'); break;
    					case '\b': appendChar(buff,'\\'); appendChar(buff,'b'); break;
    					case '\r': appendChar(buff,'\\'); appendChar(buff,'r'); break;
    					case '\f': appendChar(buff,'\\'); appendChar(buff,'f'); break;
    					case '\v': appendChar(buff,'\\'); appendChar(buff,'v'); break;
    					case '\a': appendChar(buff,'\\'); appendChar(buff,'a'); break;
    					case '\\': appendChar(buff,'\\'); appendChar(buff,'\\'); break;
    					case '\'': appendChar(buff,'\\'); appendChar(buff,'\''); break;
                        case '\"': appendChar(buff,'\\'); appendChar(buff,'\"'); break;
                        case '{': appendStr(buff,SCOPE()); break;
                        case '}': appendStr(buff,UNSCOPE()); break;
                        case '<': appendStr(buff,LTN()); break;
                        case '>': appendStr(buff,GTN()); break;
                        case '&': appendStr(buff,AMP()); break;
    					default: appendChar(buff,*pcn);
    				}
    			}
    			ret = asString(buff);
    		}
    		else ret = "";
    	}
    	else ret = NULL;
        return ret;
    }
    return name;
}
/******************************************************************************/
// Function: convert spec.symbols to esc sequences and single-quote if necessary
char* ProperName(__in __nullterminated char* name)
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
    CQuickBytes *buff = g_szBuf_ProperName;
    _ASSERTE (buff);
    if(g_fUseProperName)
    {
    	char *ret;
        BOOL fQuoted;
    	if(name)
    	{
    		if(*name)
    		{
                buff->Shrink(0);
                fQuoted = IsNameToQuote(name);
    			if(fQuoted) appendChar(buff,'\'');
                appendStr(buff,UnquotedProperName(name));
    			if(fQuoted) appendChar(buff,'\'');
    			ret = asString(buff);
    		}
    		else ret = "";
    	}
    	else ret = NULL;
        return ret;
    }
    return name;
}

#endif

/******************************************************************************/
const char* PrettyPrintSig(
    PCCOR_SIGNATURE typePtr,            // type to convert,     
	unsigned typeLen,					// the lenght of 'typePtr' 
    const char* name,                   // can be "", the name of the method for this sig 0 means local var sig 
    CQuickBytes *out,                   // where to put the pretty printed string   
    IMDInternalImport *pIMDI,           // ptr to IMDInternalImport class with ComSig
	const char* inlabel,				// prefix for names (NULL if no names required)
    BOOL printTyArity)
{
    STATIC_CONTRACT_THROWS;
    
    PAL_TRY {
    	PrettyPrintSignature(typePtr, typeLen, name, out, pIMDI, inlabel,printTyArity);
    } PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
        out->Shrink(0);
        appendStr(out,"ERROR PARSING THE SIGNATURE");
    } PAL_ENDTRY

    return(asString(out));  
}

/********************************************************************************/
// Converts a com signature to a printable signature.
// Note that return value is pointing at the CQuickBytes buffer, 

const PCCOR_SIGNATURE PrettyPrintSignature(
    PCCOR_SIGNATURE typePtr,            // type to convert,     
	unsigned typeLen,					// the lenght of 'typePtr' 
    const char* name,                   // can be "", the name of the method for this sig 0 means local var sig 
    CQuickBytes *out,                   // where to put the pretty printed string   
    IMDInternalImport *pIMDI,           // ptr to IMDInternalImport class with ComSig
	const char* inlabel,				// prefix for names (NULL if no names required)
    BOOL printTyArity)
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
    unsigned numArgs;
    unsigned numTyArgs = 0;
    PCCOR_SIGNATURE typeEnd = typePtr + typeLen;
	unsigned ixArg= 0; //arg index
	char argname[1024];
	char label[16];
    const char* openpar = "(";
    const char* closepar = ")";
	ParamDescriptor* pszArgName = NULL; // ptr to array of names (if provided by debug info)

	if(inlabel && *inlabel) // check for *inlabel is totally unnecessary, added to pacify the PREFIX
	{
		strcpy_s(label,COUNTOF(label),inlabel);
		ixArg = label[strlen(label)-1] - '0';
		label[strlen(label)-1] = 0;
		if(label[0] == '@') // it's pointer!
		{
			pszArgName = (ParamDescriptor*)(size_t)atoi(&label[1]);
		}
	}

    if (name != 0)        // 0 means a local var sig  
    {
            // get the calling convention out   
        unsigned callConv = CorSigUncompressData(typePtr);  

        if (isCallConv(callConv, IMAGE_CEE_CS_CALLCONV_FIELD))
        {
            typePtr = PrettyPrintTypeOrDef(typePtr, out, pIMDI);   
            if (*name)    
            {   
                appendChar(out, ' ');
				appendStr(out, name);   
            }   
            return(typePtr);  
        }

        if (callConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)   
            appendStr(out, KEYWORD("explicit "));    

        if (callConv & IMAGE_CEE_CS_CALLCONV_HASTHIS)   
            appendStr(out, KEYWORD("instance "));

        if (isCallConv(callConv, IMAGE_CEE_CS_CALLCONV_GENERICINST))
        {
          openpar = LTN();
          closepar = GTN();
        }
        else
    	{
            static char* callConvNames[8] = {   
                "", 
                "unmanaged cdecl ", 
                "unmanaged stdcall ",   
                "unmanaged thiscall ",  
                "unmanaged fastcall ",  
                "vararg ",   
                "<error> ",   
                "<error> "   
                };  
            appendStr(out, KEYWORD(callConvNames[callConv & 7]));    
        }

    	if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
    	{
    	  numTyArgs = CorSigUncompressData(typePtr);
    	}
        numArgs = CorSigUncompressData(typePtr);
        if (!isCallConv(callConv, IMAGE_CEE_CS_CALLCONV_GENERICINST))
	    {
                // do return type   
    		if(pszArgName)
    		{
    			argname[0] = 0;
    			DumpParamAttr(argname,COUNTOF(argname),pszArgName[ixArg+numArgs].attr);
    			appendStr(out,argname);
    		}
            typePtr = PrettyPrintTypeOrDef(typePtr, out, pIMDI); 
    		if(pszArgName)
    		{
    			argname[0] = ' '; argname[1] = 0;
    			DumpMarshaling(pIMDI,argname,COUNTOF(argname),pszArgName[ixArg+numArgs].tok);
    			appendStr(out,argname);
    		}
    		if(*name != 0)
    		{
    			appendChar(out, ' ');    
    			appendStr(out, name);   
    		}
            if((numTyArgs != 0)&&printTyArity)
            {
                appendStr(out,LTN());
                appendChar(out,'[');
                appendStrNum(out,numTyArgs);
                appendChar(out,']');
                appendStr(out,GTN());
            }
        }
    }
    else    
        numArgs = CorSigUncompressData(typePtr);    

    appendStr(out, openpar);    

	bool needComma = false;
	while(typePtr < typeEnd) 
	{
		if(name) // printing the arguments
		{
            PREFIX_ASSUME(typePtr != NULL);
			if (*typePtr == ELEMENT_TYPE_SENTINEL) 
			{
				if (needComma)
					appendChar(out, ',');    
				appendStr(out, "...");    
				typePtr++;
			}
			else 
			{
				if (numArgs <= 0)
					break;
				if (needComma)
					appendChar(out, ',');    
				if(pszArgName)
				{
					argname[0] = 0;
					DumpParamAttr(argname,COUNTOF(argname),pszArgName[ixArg].attr);
					appendStr(out,argname);
				}
				typePtr = PrettyPrintTypeOrDef(typePtr, out, pIMDI); 
				if(inlabel)
				{
					if(pszArgName)
					{
						argname[0] = ' '; argname[1] = 0;
						DumpMarshaling(pIMDI,argname,COUNTOF(argname),pszArgName[ixArg].tok);
						strcat_s(argname, COUNTOF(argname), ProperName(pszArgName[ixArg++].name));
					}
					else sprintf_s(argname,COUNTOF(argname)," %s_%d",label,ixArg++);
					appendStr(out,argname);
				}
				--numArgs;  
			}
		}
		else // printing local vars
		{
			if (numArgs <= 0)
				break;
			if(pszArgName)
			{
				if(pszArgName[ixArg].attr == 0xFFFFFFFF)
				{
					CQuickBytes fake_out;
					typePtr = PrettyPrintTypeOrDef(typePtr, &fake_out, pIMDI); 
					ixArg++;
					numArgs--;
					continue;
				}
			}
			if (needComma)
                appendChar(out, ',');    
			if(pszArgName)
			{
				sprintf_s(argname,COUNTOF(argname),"[%d] ",pszArgName[ixArg].attr);
				appendStr(out,argname);
			}
			typePtr = PrettyPrintTypeOrDef(typePtr, out, pIMDI); 
			if(inlabel)
			{
				if(pszArgName)
				{
					sprintf_s(argname,COUNTOF(argname)," %s",ProperName(pszArgName[ixArg++].name));
				}
				else sprintf_s(argname,COUNTOF(argname)," %s_%d",label,ixArg++);
				appendStr(out,argname);
			}
			--numArgs;  
		}
		needComma = true;
    }
		// Have we finished printing all the arguments?
	if (numArgs > 0) {
		appendStr(out, ERRORMSG(" [SIGNATURE ENDED PREMATURELY]"));    
	}
		
    appendStr(out, closepar);    
	return(typePtr);
}


/******************************************************************************/
// pretty prints 'type' or its 'typedef' to the buffer 'out' returns a poitner to the next type, 
// or 0 on a format failure; outside ILDASM -- simple wrapper for PrettyPrintType 

PCCOR_SIGNATURE PrettyPrintTypeOrDef(
    PCCOR_SIGNATURE typePtr,            // type to convert,     
    CQuickBytes *out,                   // where to put the pretty printed string   
    IMDInternalImport *pIMDI)           // ptr to IMDInternal class with ComSig
{
    CONTRACTL
    {
        THROWS;
        SO_TOLERANT;
    }
    CONTRACTL_END;

    PCCOR_SIGNATURE pBegin, pEnd=NULL;

    BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(ThrowStackOverflow());
        
#ifdef __ILDASM__
    ULONG L = (ULONG)(out->Size());
#endif
    pBegin = typePtr;
    pEnd = PrettyPrintType(typePtr,out,pIMDI);
#ifdef __ILDASM__
    if(pEnd > pBegin) // PrettyPrintType can return NULL
    {
        DWORD i;
        ULONG l = (ULONG)(pEnd - pBegin);
        for(i=0; i < g_NumTypedefs; i++)
        {
            if(((*g_typedefs)[i].cb == l)
               && (memcmp((*g_typedefs)[i].psig,pBegin,l)==0))
            {
                out->Shrink(L); // discard output of PrettyPrintType
                appendStr(out, JUMPPT(ProperName((*g_typedefs)[i].szName),(*g_typedefs)[i].tkSelf));
                break;
            }
        }
    }
#endif
    END_SO_INTOLERANT_CODE;
    return pEnd;
}

/******************************************************************************/
// pretty prints 'type' to the buffer 'out' returns a pointer to the next type, 
// or 0 on a format failure 

PCCOR_SIGNATURE PrettyPrintType(
    PCCOR_SIGNATURE typePtr,            // type to convert,     
    CQuickBytes *out,                   // where to put the pretty printed string   
    IMDInternalImport *pIMDI)           // ptr to IMDInternal class with ComSig
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
    mdToken  tk;    
    const char* str;    
	//bool isValueArray;
	int typ;
	CQuickBytes tmp;
	CQuickBytes Appendix;
	BOOL Reiterate;
    int n;

	do {
		Reiterate = FALSE;
		switch(typ = *typePtr++) {    
			case ELEMENT_TYPE_VOID          :   
				str = "void"; goto APPEND;  
			case ELEMENT_TYPE_BOOLEAN       :   
				str = "bool"; goto APPEND;  
			case ELEMENT_TYPE_CHAR          :   
				str = "char"; goto APPEND; 
			case ELEMENT_TYPE_I1            :   
				str = "int8"; goto APPEND;  
			case ELEMENT_TYPE_U1            :   
				str = "uint8"; goto APPEND; 
			case ELEMENT_TYPE_I2            :   
				str = "int16"; goto APPEND; 
			case ELEMENT_TYPE_U2            :   
				str = "uint16"; goto APPEND;    
			case ELEMENT_TYPE_I4            :   
				str = "int32"; goto APPEND; 
			case ELEMENT_TYPE_U4            :   
				str = "uint32"; goto APPEND;    
			case ELEMENT_TYPE_I8            :   
				str = "int64"; goto APPEND; 
			case ELEMENT_TYPE_U8            :   
				str = "uint64"; goto APPEND;    
			case ELEMENT_TYPE_R4            :   
				str = "float32"; goto APPEND;   
			case ELEMENT_TYPE_R8            :   
				str = "float64"; goto APPEND;   
			case ELEMENT_TYPE_U             :   
				str = "native uint"; goto APPEND;   
			case ELEMENT_TYPE_I             :   
				str = "native int"; goto APPEND;    
			case ELEMENT_TYPE_R             :   
				str = "native float"; goto APPEND;  
			case ELEMENT_TYPE_OBJECT        :   
				str = "object"; goto APPEND;    
			case ELEMENT_TYPE_STRING        :   
				str = "string"; goto APPEND;    
			case ELEMENT_TYPE_TYPEDBYREF        :   
				str = "typedref"; goto APPEND;    
			APPEND: 
				appendStr(out, KEYWORD((char*)str));    
				break;  

			case ELEMENT_TYPE_VALUETYPE    :   
				str = "valuetype ";   
				goto DO_CLASS;  
			case ELEMENT_TYPE_CLASS         :   
				str = "class "; 
				goto DO_CLASS;  

			DO_CLASS:
				appendStr(out, KEYWORD((char*)str));
				typePtr += CorSigUncompressToken(typePtr, &tk); 
                if(IsNilToken(tk))
				{
					appendStr(out, "[ERROR! NIL TOKEN]");
				}
				else PrettyPrintClass(out, tk, pIMDI);
                REGISTER_REF(g_tkRefUser,tk)
				break;  

			case ELEMENT_TYPE_SZARRAY    :   
				insertStr(&Appendix,"[]");
				Reiterate = TRUE;
				break;
			case ELEMENT_TYPE_ARRAY       :   
				{   
				typePtr = PrettyPrintTypeOrDef(typePtr, out, pIMDI);
                PREFIX_ASSUME(typePtr != NULL);
				unsigned rank = CorSigUncompressData(typePtr);  
				if (rank == 0) {
					appendStr(out, ERRORMSG("[BAD: RANK == 0!]"));
				}
				else {
					_ASSERTE(rank != 0);
					int* lowerBounds = (int*) _alloca(sizeof(int)*2*rank);
					int* sizes       = &lowerBounds[rank];  
					memset(lowerBounds, 0, sizeof(int)*2*rank); 
					
					unsigned numSizes = CorSigUncompressData(typePtr);  
					_ASSERTE(numSizes <= rank);
				    unsigned i;
					for(i =0; i < numSizes; i++)
						sizes[i] = CorSigUncompressData(typePtr);   
					
					unsigned numLowBounds = CorSigUncompressData(typePtr);  
					_ASSERTE(numLowBounds <= rank); 
					for(i = 0; i < numLowBounds; i++)   
						typePtr+=CorSigUncompressSignedInt(typePtr,&lowerBounds[i]); 
					
					appendChar(out, '[');    
					if (rank == 1 && numSizes == 0 && numLowBounds == 0)
						appendStr(out, "...");  
					else {
						for(i = 0; i < rank; i++)   
						{   
							//if (sizes[i] != 0 || lowerBounds[i] != 0)   
							{   
								if (lowerBounds[i] == 0 && i < numSizes)    
									appendStrNum(out, sizes[i]);    
								else    
								{   
									if(i < numLowBounds)
									{
										appendStrNum(out, lowerBounds[i]);  
										appendStr(out, "...");  
										if (/*sizes[i] != 0 && */i < numSizes)  
											appendStrNum(out, lowerBounds[i] + sizes[i] - 1);   
									}
								}   
							}   
							if (i < rank-1) 
                                appendChar(out, ',');    
						}   
					}
					appendChar(out, ']'); 
				}
				} break;    

			case ELEMENT_TYPE_VAR        :   
                appendChar(out, '!');
                n  = CorSigUncompressData(typePtr);
#ifdef __ILDASM__
                if(!PrettyPrintGP(g_tkVarOwner,out,n))
#endif
    				appendStrNum(out, n);
				break;

			case ELEMENT_TYPE_MVAR        :   
                appendChar(out, '!');    
                appendChar(out, '!');    
                n  = CorSigUncompressData(typePtr);
#ifdef __ILDASM__
                if(!PrettyPrintGP(g_tkMVarOwner,out,n))
#endif
    				appendStrNum(out, n);
				break;

			case ELEMENT_TYPE_FNPTR :   
				appendStr(out, KEYWORD("method "));  
				typePtr = PrettyPrintSignature(typePtr, 0x7FFF, "*", out, pIMDI, NULL);
				break;

            case ELEMENT_TYPE_GENERICINST :
            {
			  typePtr = PrettyPrintTypeOrDef(typePtr, out, pIMDI);
              appendStr(out, LTN());    
			  unsigned numArgs = CorSigUncompressData(typePtr);    
			  bool needComma = false;
			  while(numArgs--)
              {
			      if (needComma)
                      appendChar(out, ',');    
			      typePtr = PrettyPrintTypeOrDef(typePtr, out, pIMDI); 
			      needComma = true;
			  }
              appendStr(out, GTN());    
			  break;
			}

#ifdef LOGGING
            case ELEMENT_TYPE_INTERNAL :
                char sz[32];
                void* pMT;
                typePtr += CorSigUncompressPointer(typePtr, &pMT);
                sprintf_s(sz, COUNTOF(sz),"MT: %p", pMT);
                appendStr(out, sz);
                break;
#endif // LOGGING                
		
		
				// Modifiers or depedent types  
			case ELEMENT_TYPE_CMOD_OPT	:
				str = " modopt("; goto ADDCLASSTOCMOD;	
			case ELEMENT_TYPE_CMOD_REQD	:
				str = " modreq(";
			ADDCLASSTOCMOD:
				typePtr += CorSigUncompressToken(typePtr, &tk); 
                _ASSERTE(!IsNilToken(tk) && "Nil token in custom modifier");
				tmp.Shrink(0);
				appendStr(&tmp, KEYWORD((char*)str));
				PrettyPrintClass(&tmp, tk, pIMDI);
				appendChar(&tmp,')');
				str = (const char *) asString(&tmp);
				goto MODIFIER;	
			case ELEMENT_TYPE_PINNED	:
				str = " pinned"; goto MODIFIER;	
			case ELEMENT_TYPE_PTR           :   
				str = "*"; goto MODIFIER;   
			case ELEMENT_TYPE_BYREF         :   
				str = AMP(); goto MODIFIER;   
			MODIFIER:
				insertStr(&Appendix, str);
				Reiterate = TRUE;
				break;  

			default:    
			case ELEMENT_TYPE_SENTINEL      :   
			case ELEMENT_TYPE_END           :   
				//_ASSERTE(!"Unknown Type");
				if(typ)
				{
					char sz[64];
					sprintf_s(sz,COUNTOF(sz),"/* UNKNOWN TYPE (0x%X)*/",typ);
					appendStr(out, ERRORMSG(sz));
				}
				break;  
		} // end switch
	} while(Reiterate);
	appendStr(out,asString(&Appendix));
    return(typePtr);    
}

/******************************************************************/
const char* PrettyPrintClass(
    CQuickBytes *out,                   // where to put the pretty printed string   
	mdToken tk,					 		// The class token to look up 
    IMDInternalImport *pIMDI)           // ptr to IMDInternalImport class with ComSig
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;
    
    if(tk == mdTokenNil)  // Zero resolution scope for "somewhere here" TypeRefs
    {
		appendStr(out,"[*]");
		return(asString(out));
    }
	if(!pIMDI->IsValidToken(tk))
	{
		char str[1024];
		sprintf_s(str,COUNTOF(str)," [ERROR: INVALID TOKEN 0x%8.8X] ",tk);
		appendStr(out,ERRORMSG(str));
		return(asString(out));
	}
	switch(TypeFromToken(tk))
	{
		case mdtTypeRef:
        case mdtTypeDef:
#ifdef __ILDASM__
            DWORD ix;
            for(ix = 0; ix < g_NumTypedefs; ix++)
            {
                if((*g_typedefs)[ix].tkTypeSpec == tk) break;
            }
            if(ix < g_NumTypedefs)
            {
                appendStr(out,JUMPPT(ProperName((*g_typedefs)[ix].szName),(*g_typedefs)[ix].tkSelf));
            }
            else
#endif
			{
				const char *nameSpace = 0;  
				const char *name = 0;
				mdToken tkEncloser;
				
				if (TypeFromToken(tk) == mdtTypeRef)
				{
					tkEncloser = pIMDI->GetResolutionScopeOfTypeRef(tk);
					pIMDI->GetNameOfTypeRef(tk, &nameSpace, &name);
				}
				else 
				{
					if(FAILED(pIMDI->GetNestedClassProps(tk,&tkEncloser))) tkEncloser = mdTypeDefNil;
					pIMDI->GetNameOfTypeDef(tk, &name, &nameSpace);
				}
				MAKE_NAME_IF_NONE(name,tk);
				if((tkEncloser == mdTokenNil) || RidFromToken(tkEncloser))
				{
					PrettyPrintClass(out,tkEncloser,pIMDI);
					if (TypeFromToken(tkEncloser) == mdtTypeRef || TypeFromToken(tkEncloser) == mdtTypeDef)
					{
                        appendChar(out, '/');    
						//nameSpace = ""; //don't print namespaces for nested classes!
					}
				}
				if(TypeFromToken(tk)==mdtTypeDef)
				{
					unsigned L = (unsigned)strlen(ProperName((char*)name))+1;
					char* szFN = NULL;
					if(nameSpace && *nameSpace)
					{
						char* sz = ProperName((char*)nameSpace);
						L+= (unsigned)strlen(sz)+1;
						szFN = new char[L];
						sprintf_s(szFN,L,"%s.",sz);
					}
					else
					{
						szFN = new char[L];
						*szFN = 0;
					}
					strcat_s(szFN,L, ProperName((char*)name));
					appendStr(out,JUMPPT(szFN,tk));
					VDELETE(szFN);
				}
				else
				{
					if (nameSpace && *nameSpace) {
						appendStr(out, ProperName((char*)nameSpace));  
                        appendChar(out, '.');    
					}

					appendStr(out, ProperName((char*)name));
				}
				if(g_fDumpTokens)
				{
					char tmp[16];
					sprintf_s(tmp,COUNTOF(tmp),"/*%08X*/",tk);
					appendStr(out,COMMENT(tmp));
				}
			}
			break;

		case mdtAssemblyRef:
			{
				LPCSTR	szName = NULL;
#ifdef __ILDASM__
				if(rAsmRefName && (RidFromToken(tk) <= ulNumAsmRefs)) szName = rAsmRefName[RidFromToken(tk)-1];
				else 
#endif                    
                    pIMDI->GetAssemblyRefProps(tk,NULL,NULL,&szName,NULL,NULL,NULL,NULL);
				if(szName && *szName)
				{
                    appendChar(out, '[');    
					appendStr(out,JUMPPT(ProperName((char*)szName),tk));
					if(g_fDumpTokens)
					{
						char tmp[16];
						sprintf_s(tmp,COUNTOF(tmp),"/*%08X*/",tk);
						appendStr(out,COMMENT(tmp));
					}
                    appendChar(out, ']');    
				}
			}
			break;
		case mdtAssembly:
			{
				LPCSTR	szName = NULL;
				pIMDI->GetAssemblyProps(tk,NULL,NULL,NULL,&szName,NULL,NULL);
				if(szName && *szName)
				{
                    appendChar(out, '[');    
					appendStr(out,JUMPPT(ProperName((char*)szName),tk));
					if(g_fDumpTokens)
					{
						char tmp[16];
						sprintf_s(tmp,COUNTOF(tmp),"/* %08X */",tk);
						appendStr(out,COMMENT(tmp));
					}
                    appendChar(out, ']');    
				}
			}
			break;
		case mdtModuleRef:
			{
				LPCSTR	szName = NULL;
				pIMDI->GetModuleRefProps(tk,&szName);
				if(szName && *szName)
				{
                    appendChar(out, '[');    
					appendStr(out,KEYWORD(".module "));
					appendStr(out,JUMPPT(ProperName((char*)szName),tk));
					if(g_fDumpTokens)
					{
						char tmp[16];
						sprintf_s(tmp,COUNTOF(tmp),"/*%08X*/",tk);
						appendStr(out,COMMENT(tmp));
					}
                    appendChar(out, ']');    
				}
			}
			break;

		case mdtTypeSpec:
			{
#ifdef __ILDASM__
                DWORD ix;
                for(ix = 0; ix < g_NumTypedefs; ix++)
                {
                    if((*g_typedefs)[ix].tkTypeSpec == tk) break;
                }
                if(ix < g_NumTypedefs)
                {
                    appendStr(out,JUMPPT(ProperName((*g_typedefs)[ix].szName),(*g_typedefs)[ix].tkSelf));
                }
                else
#endif
                {
                    ULONG cSig;
                    PCCOR_SIGNATURE sig = pIMDI->GetSigFromToken(tk, &cSig);
                    PrettyPrintType(sig, out, pIMDI);
                }
				if(g_fDumpTokens)
				{
					char tmp[16];
					sprintf_s(tmp,COUNTOF(tmp),"/*%08X*/",tk);
					appendStr(out,COMMENT(tmp));
				}
			}
            break;

        case mdtModule:
            break;
		
        default:
			{
				char str[128];
				sprintf_s(str,COUNTOF(str)," [ERROR: INVALID TOKEN TYPE 0x%8.8X] ",tk);
				appendStr(out,ERRORMSG(str));
			}
	}
	return(asString(out));
}

char* DumpSimpleNativeType(ULONG ulData)
{
    char* sz;
    switch (ulData)
    {
        case NATIVE_TYPE_VOID:		sz = " void"; break;
        case NATIVE_TYPE_BOOLEAN:	sz = " bool"; break;
        case NATIVE_TYPE_I1:		sz = " int8"; break;
        case NATIVE_TYPE_U1:		sz = " unsigned int8"; break;
        case NATIVE_TYPE_I2:		sz = " int16"; break;
        case NATIVE_TYPE_U2:		sz = " unsigned int16"; break;
        case NATIVE_TYPE_I4:		sz = " int32"; break;
        case NATIVE_TYPE_U4:		sz = " unsigned int32"; break;
        case NATIVE_TYPE_I8:		sz = " int64"; break;
        case NATIVE_TYPE_U8:		sz = " unsigned int64"; break;
        case NATIVE_TYPE_R4:		sz = " float32"; break;
        case NATIVE_TYPE_R8:		sz = " float64"; break;
        case NATIVE_TYPE_SYSCHAR:	sz = " syschar"; break;
        case NATIVE_TYPE_VARIANT:	sz = " variant"; break;
        case NATIVE_TYPE_CURRENCY:	sz = " currency"; break;
        case NATIVE_TYPE_DECIMAL:	sz = " decimal"; break;
        case NATIVE_TYPE_DATE:		sz = " date"; break;
        case NATIVE_TYPE_BSTR:		sz = " bstr"; break;
        case NATIVE_TYPE_LPSTR:		sz = " lpstr"; break;
        case NATIVE_TYPE_LPWSTR:	sz = " lpwstr"; break;
        case NATIVE_TYPE_LPTSTR:	sz = " lptstr"; break;
        case NATIVE_TYPE_OBJECTREF: sz = " objectref"; break;
        case NATIVE_TYPE_STRUCT:	sz = " struct"; break;
        case NATIVE_TYPE_ERROR:		sz = " error"; break;
        case NATIVE_TYPE_INT:		sz = " int"; break;
        case NATIVE_TYPE_UINT:		sz = " uint"; break;
        case NATIVE_TYPE_NESTEDSTRUCT: sz = " nested struct"; break;
        case NATIVE_TYPE_BYVALSTR:	sz = " byvalstr"; break;
        case NATIVE_TYPE_ANSIBSTR:	sz = " ansi bstr"; break;
        case NATIVE_TYPE_TBSTR:		sz = " tbstr"; break;
        case NATIVE_TYPE_VARIANTBOOL: sz = " variant bool"; break;
        case NATIVE_TYPE_FUNC:		sz = " method"; break;
        case NATIVE_TYPE_ASANY:		sz = " as any"; break;
        case NATIVE_TYPE_LPSTRUCT:	sz = " lpstruct"; break;
        default: sz = "";
    }
    return sz;
}

char* DumpMarshaling(IMDInternalImport* pImport, 
                     __inout_ecount(cchszString) char* szString, 
                     DWORD cchszString, 
                     mdToken tok)
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;

	PCCOR_SIGNATURE pSigNativeType;
	ULONG			cbNativeType;
    SString         buf;
	if(RidFromToken(tok) && SUCCEEDED(pImport->GetFieldMarshal(				// return error if no native type associate with the token
											tok,						// [IN] given fielddef
											&pSigNativeType,	// [OUT] the native type signature
											&cbNativeType)))	// [OUT] the count of bytes of *ppvNativeType
	{
        ULONG cbCur = 0;
        ULONG ulData;
		char*	sz = NULL;
		BOOL  fAddAsterisk = FALSE, fAddBrackets = FALSE;
        buf.AppendPrintf(" %s(", KEYWORD("marshal"));
        while (cbCur < cbNativeType)
        {
			ulData = NATIVE_TYPE_MAX;
            cbCur += CorSigUncompressData(&pSigNativeType[cbCur], &ulData);
            sz = DumpSimpleNativeType(ulData);
            if(*sz == 0)
            {
                switch (ulData)
                {
                case NATIVE_TYPE_PTR:		sz = ""; fAddAsterisk = TRUE; break;
                case NATIVE_TYPE_SAFEARRAY: 
                    sz = "";
                    buf.AppendASCII(KEYWORD(" safearray"));
                    ulData = VT_EMPTY;
                    if (cbCur < cbNativeType)
                    {
                        cbCur += CorSigUncompressData(&pSigNativeType[cbCur], &ulData);
                    }
                    switch(ulData & VT_TYPEMASK)
                    {
                        case VT_EMPTY:				sz=""; break;
                        case VT_NULL:				sz=" null"; break;
                        case VT_VARIANT:			sz=" variant"; break;
                        case VT_CY:					sz=" currency"; break;
                        case VT_VOID:				sz=" void"; break;
                        case VT_BOOL:				sz=" bool"; break;
                        case VT_I1:					sz=" int8"; break;
                        case VT_I2:					sz=" int16"; break;
                        case VT_I4:					sz=" int32"; break;
                        case VT_I8:					sz=" int64"; break;
                        case VT_R4:					sz=" float32"; break;
                        case VT_R8:					sz=" float64"; break;
                        case VT_UI1:				sz=" unsigned int8"; break;
                        case VT_UI2:				sz=" unsigned int16"; break;
                        case VT_UI4:				sz=" unsigned int32"; break;
                        case VT_UI8:				sz=" unsigned int64"; break;
                        case VT_PTR:				sz=" *"; break;
                        case VT_DECIMAL:			sz=" decimal"; break;
                        case VT_DATE:				sz=" date"; break;
                        case VT_BSTR:				sz=" bstr"; break;
                        case VT_LPSTR:				sz=" lpstr"; break;
                        case VT_LPWSTR:				sz=" lpwstr"; break;
                        case VT_UNKNOWN:			sz=" iunknown"; break;
                        case VT_DISPATCH:			sz=" idispatch"; break;
                        case VT_SAFEARRAY:			sz=" safearray"; break;
                        case VT_INT:				sz=" int"; break;
                        case VT_UINT:				sz=" unsigned int"; break;
                        case VT_ERROR:				sz=" error"; break;
                        case VT_HRESULT:			sz=" hresult"; break;
                        case VT_CARRAY:				sz=" carray"; break;
                        case VT_USERDEFINED:		sz=" userdefined"; break;
                        case VT_RECORD:				sz=" record"; break;
                        case VT_FILETIME:			sz=" filetime"; break;
                        case VT_BLOB:				sz=" blob"; break;
                        case VT_STREAM:				sz=" stream"; break;
                        case VT_STORAGE:			sz=" storage"; break;
                        case VT_STREAMED_OBJECT:	sz=" streamed_object"; break;
                        case VT_STORED_OBJECT:		sz=" stored_object"; break;
                        case VT_BLOB_OBJECT:		sz=" blob_object"; break;
                        case VT_CF:					sz=" cf"; break;
                        case VT_CLSID:				sz=" clsid"; break;
                        default:					sz=NULL; break;
                    }
                    if(sz) buf.AppendASCII(KEYWORD(sz));
                    else buf.AppendPrintf(ERRORMSG(" [ILLEGAL VARIANT TYPE 0x%X]"),ulData & VT_TYPEMASK);
                    sz="";
                    switch(ulData & (~VT_TYPEMASK))
                    {
                        case VT_ARRAY: sz = "[]"; break;
                        case VT_VECTOR: sz = " vector"; break;
                        case VT_BYREF: sz = "&"; break; 
                        case VT_BYREF|VT_ARRAY: sz = "&[]"; break; 
                        case VT_BYREF|VT_VECTOR: sz = "& vector"; break; 
                        case VT_ARRAY|VT_VECTOR: sz = "[] vector"; break; 
                        case VT_BYREF|VT_ARRAY|VT_VECTOR: sz = "&[] vector"; break; 
                    }
                    buf.AppendASCII(KEYWORD(sz));
                    sz="";

                    // Extract the user	defined	sub	type name.
                    if (cbCur < cbNativeType)
                    {
                        LPUTF8 strTemp = NULL;
                        int	strLen = 0;
                        int	ByteCountLength	= 0;
                        strLen = GetLength(&pSigNativeType[cbCur], &ByteCountLength);
                        cbCur += ByteCountLength;
                        if(strLen)
                        {
                            strTemp	= (LPUTF8)_alloca(strLen + 1);
                            memcpy(strTemp,	(LPUTF8)&pSigNativeType[cbCur],	strLen);
                            strTemp[strLen]	= 0;
                            buf.AppendPrintf(", \"%s\"", UnquotedProperName(strTemp));
                            cbCur += strLen;
                        }
                    }
                    break;

                case NATIVE_TYPE_ARRAY:		sz = ""; fAddBrackets = TRUE; break;

                case NATIVE_TYPE_FIXEDSYSSTRING:
                    {
                        sz = "";
                        buf.AppendASCII(KEYWORD(" fixed sysstring"));
                        buf.AppendASCII(" [");
                        if (cbCur < cbNativeType)
                        {
                            cbCur += CorSigUncompressData(&pSigNativeType[cbCur], &ulData);
                            buf.AppendPrintf("%d",ulData);
                        }
                        buf.AppendASCII("]");
                    }
                    break;
                case NATIVE_TYPE_FIXEDARRAY:
                    {
                        sz = "";
                        buf.AppendASCII(KEYWORD(" fixed array"));
                        buf.AppendASCII(" [");
                        if (cbCur < cbNativeType)
                        {
                            cbCur += CorSigUncompressData(&pSigNativeType[cbCur], &ulData);
                            buf.AppendPrintf("%d",ulData);
                        }
                        buf.AppendASCII("]");
                        if (cbCur < cbNativeType)
                        {
                            cbCur += CorSigUncompressData(&pSigNativeType[cbCur], &ulData);
                            sz = DumpSimpleNativeType(ulData);
                        }
                    }
                    break;

                case NATIVE_TYPE_INTF:
                        buf.AppendASCII(KEYWORD(" interface"));
                        goto DumpIidParamIndex;
                case NATIVE_TYPE_IUNKNOWN:
                        buf.AppendASCII(KEYWORD(" iunknown"));
                        goto DumpIidParamIndex;
                case NATIVE_TYPE_IDISPATCH:
                         buf.AppendASCII(KEYWORD(" idispatch"));
                     DumpIidParamIndex:
                         sz = " ";
                         if (cbCur < cbNativeType)
                         {
                             cbCur += CorSigUncompressData(&pSigNativeType[cbCur], &ulData);
                             buf.AppendPrintf("(%s = %d)",KEYWORD("iidparam"),ulData);
                         }
                         break;

                case NATIVE_TYPE_CUSTOMMARSHALER:
                    {
                        LPUTF8 strTemp = NULL;
                        int strLen = 0;
                        int ByteCountLength = 0;
                        BOOL fFourStrings = FALSE;

                        sz = "";
                        buf.AppendASCII(KEYWORD(" custom"));
                        buf.AppendASCII(" (");
                        // Extract the typelib GUID.
                        strLen = GetLength(&pSigNativeType[cbCur], &ByteCountLength);
                        cbCur += ByteCountLength;
                        if(strLen)
                        {
                            fFourStrings = TRUE;
                            strTemp = (LPUTF8)(new char[strLen + 1]);
                            if(strTemp)
                            {
                                memcpy(strTemp, (LPUTF8)&pSigNativeType[cbCur], strLen);
                                strTemp[strLen] = 0;
                                buf.AppendPrintf("\"%s\",",UnquotedProperName(strTemp));
                                cbCur += strLen;
                                VDELETE(strTemp);
                            }
                        }
                        if(cbCur >= cbNativeType)
                            buf.AppendASCII(ERRORMSG("/* INCOMPLETE MARSHALER INFO */"));
                        else
                        {
                            //_ASSERTE(cbCur < cbNativeType);

                            // Extract the name of the native type.
                            strLen = GetLength(&pSigNativeType[cbCur], &ByteCountLength);
                            cbCur += ByteCountLength;
                            if(fFourStrings)
                            {
                                if(strLen)
                                {
                                    strTemp = (LPUTF8)(new char[strLen + 1]);
                                    if(strTemp)
                                    {
                                        memcpy(strTemp, (LPUTF8)&pSigNativeType[cbCur], strLen);
                                        strTemp[strLen] = 0;
                                        buf.AppendPrintf("\"%s\",",UnquotedProperName(strTemp));
                                        cbCur += strLen;
                                        VDELETE(strTemp);
                                    }
                                }
                                else buf.AppendASCII("\"\",");
                            }
                            if(cbCur >= cbNativeType)
                                buf.AppendASCII(ERRORMSG("/* INCOMPLETE MARSHALER INFO */"));
                            else
                            {
                                //_ASSERTE(cbCur < cbNativeType);

                                // Extract the name of the custom marshaler.
                                strLen = GetLength(&pSigNativeType[cbCur], &ByteCountLength);
                                cbCur += ByteCountLength;
                                if(strLen)
                                {
                                    strTemp = (LPUTF8)(new char[strLen + 1]);
                                    if(strTemp)
                                    {
                                        memcpy(strTemp, (LPUTF8)&pSigNativeType[cbCur], strLen);
                                        strTemp[strLen] = 0;
                                        buf.AppendPrintf("\"%s\",",UnquotedProperName(strTemp));
                                        cbCur += strLen;
                                        VDELETE(strTemp);
                                    }
                                }
                                else buf.AppendASCII("\"\",");
                                if(cbCur >= cbNativeType)
                                    buf.AppendASCII(ERRORMSG("/* INCOMPLETE MARSHALER INFO */"));
                                else
                                {
                                    // Extract the cookie string.
                                    strLen = GetLength(&pSigNativeType[cbCur], &ByteCountLength);
                                    cbCur += ByteCountLength;
                                    if(cbCur+strLen > cbNativeType)
					                    buf.AppendASCII(ERRORMSG("/* INCOMPLETE MARSHALER INFO */"));
                                    else
                                    {
                                        if(strLen)
                                        {
                                            strTemp = (LPUTF8)(new char[strLen + 1]);
                                            if(strTemp)
                                            {
                                                memcpy(strTemp, (LPUTF8)&pSigNativeType[cbCur], strLen);
                                                strTemp[strLen] = 0;

                                                buf.AppendASCII("\"");
                                                // Copy the cookie string and transform the embedded nulls into \0's.
                                                for (int i = 0; i < strLen - 1; i++, cbCur++)
                                                {
                                                    if (strTemp[i] == 0)
                                                        buf.AppendASCII("\\0");
                                                    else
                                                    {
                                                        buf.AppendPrintf("%c", strTemp[i]);
                                                    }
                                                }
                                                buf.AppendPrintf("%c\"", strTemp[strLen - 1]);
                                                cbCur++;
                                                VDELETE(strTemp);
                                            }
                                        }
                                        else
                                            buf.AppendASCII("\"\"");
                                        //_ASSERTE(cbCur <= cbNativeType);
                                    }
                                }
                            }
                        }
                        buf.AppendASCII(")");
                    }
                    break;
                default:
                    {
                        sz = "";
                    }
                } // end switch
            }
			if(*sz)
			{
				buf.AppendASCII(KEYWORD(sz));
				if(fAddAsterisk)
				{
					buf.AppendASCII("*");
					fAddAsterisk = FALSE;
				}
				if(fAddBrackets)
				{
					ULONG ulSizeParam=(ULONG)-1,ulSizeConst=(ULONG)-1;
					buf.AppendASCII("[");
					fAddBrackets = FALSE;
                    if (cbCur < cbNativeType)
                    {
                        cbCur += CorSigUncompressData(&pSigNativeType[cbCur], &ulData);
						ulSizeParam = ulData;
                        if (cbCur < cbNativeType)
                        {
                            cbCur += CorSigUncompressData(&pSigNativeType[cbCur], &ulData);
							ulSizeConst = ulData;
                            if (cbCur < cbNativeType)
                            {
                                // retrieve flags
                                cbCur += CorSigUncompressData(&pSigNativeType[cbCur], &ulData);
                                if((ulData & 1) == 0) ulSizeParam = 0xFFFFFFFF;
                            }
                        }
                    }
					if(ulSizeConst != 0xFFFFFFFF)
					{
						buf.AppendPrintf("%d",ulSizeConst);
						if(ulSizeParam == 0) ulSizeParam = 0xFFFFFFFF; // don't need +0
					}
					if(ulSizeParam != 0xFFFFFFFF)
					{
						buf.AppendPrintf(" + %d",ulSizeParam);
					}
					buf.AppendASCII("]");
 				}

			}

			if (ulData >= NATIVE_TYPE_MAX)
				break;
        } // end while (cbCur < cbNativeType)
		// still can have outstanding asterisk or brackets
		if(fAddAsterisk)
		{
			buf.AppendASCII("*");
			fAddAsterisk = FALSE;
		}
		if(fAddBrackets)
		{
			ULONG ulSizeParam=(ULONG)-1,ulSizeConst=(ULONG)-1;
			buf.AppendASCII("[");
			fAddBrackets = FALSE;
            if (cbCur < cbNativeType)
            {
                cbCur += CorSigUncompressData(&pSigNativeType[cbCur], &ulData);
				ulSizeParam = ulData;
                if (cbCur < cbNativeType)
                {
                    cbCur += CorSigUncompressData(&pSigNativeType[cbCur], &ulData);
					ulSizeConst = ulData;
                }
            }
			if(ulSizeConst != 0xFFFFFFFF)
			{
				buf.AppendPrintf("%d",ulSizeConst);
				if(ulSizeParam == 0) ulSizeParam = 0xFFFFFFFF; // don't need +0
			}
			if(ulSizeParam != 0xFFFFFFFF)
			{
				buf.AppendPrintf(" + %d",ulSizeParam);
			}
			buf.AppendASCII("]");
 		}
		buf.AppendASCII(") ");
	}// end if(SUCCEEDED
    char * tgt = szString + strlen(szString);
    return tgt + sprintf_s(tgt, cchszString - (tgt - szString), "%S", buf.GetUnicode());
}

char* DumpParamAttr(__inout_ecount(cchszString) char* szString, DWORD cchszString, DWORD dwAttr)
{
    CONTRACTL
    {
        THROWS;
    }
    CONTRACTL_END;

	char*			szptr = &szString[strlen(szString)];
	char*			was_szptr = szptr;
	if(IsPdIn(dwAttr))
    {
        szptr+=sprintf_s(szptr,cchszString - (szptr - was_szptr), KEYWORD("[in]"));
    }
	if(IsPdOut(dwAttr))
    {
        szptr+=sprintf_s(szptr,cchszString - (szptr - was_szptr),KEYWORD("[out]"));
    }
	if(IsPdOptional(dwAttr))
    {
        szptr+=sprintf_s(szptr,cchszString - (szptr - was_szptr),KEYWORD("[opt]"));
    }
	if(szptr != was_szptr)
    {
        szptr+=sprintf_s(szptr,cchszString - (szptr - was_szptr)," ");
    }
	return szptr;

}
